/*
	usteve

  	FILE NAME:
  
  		support3d.h
  
  	DESCRIPTION:
		
		Defines constants and classes used to support 3D graphics.
*/
#include <string>
#include <cmath>
#include <iostream>
using namespace std;

#ifndef _SUPPORT3D
#define _SUPPORT3D

/*                                                  _________________________
**_________________________________________________/  Mathematical Constants \__
*/
#ifndef MATH_CONSTANTS
#define MATH_CONSTANTS
const double // MATHEMATICAL CONSTANTS
	PI = atan(1.0) * 4.0,
	TWO_PI = 2.0 * PI,
	RADIANS_PER_DEGREE = PI / 180.0,
	DEGREES_PER_RADIAN = 180.0 / PI;
#endif

/*                                                           ________________
**__________________________________________________________/  Point3 Class  \__
*/
                                                 
class Point3
{ 
public: 
   double x, y, z;

   Point3() {x = y = z = 0;} 
   // Constructs the origin, point (0, 0, 0).

   Point3(double xx, double yy, double zz) { x = xx; y = yy; z = zz; }
   // Constructs the point (xx, yy, zz).

   void set(double dx, double dy, double dz) {x = dx; y = dy; z = dz; }
   // Makes this point (dx, dy, dz).

   void set(Point3& p) { x = p.x; y = p.y; z = p.z; }
   // Makes this point a copy of p.
}; 

/*                                                          _________________
**_________________________________________________________/  Vector3 Class  \__
*/

class Vector3
{ 
public: 
	double x, y, z;

	Vector3() { x = y = z = 0; } 
	// Constructs the zero vector, (0, 0, 0).

	Vector3(double xx, double yy, double zz) { x = xx; y = yy; z = zz; }
	// Constructs the vector (xx, yy, zz).

	Vector3(const Vector3& v) { x = v.x; y = v.y; z = v.z; }
	// Constructs a copy of v.

	void set(double dx, double dy, double dz) { x = dx; y = dy; z = dz; } 
	// Makes this vector (dx, dy, dz).

	void set(Vector3& v){ x = v.x; y = v.y; z = v.z;}
	// Makes this vector a copy of p.

	void flip() { x = -x; y = -y; z = -z; } 
	// Reverse the direction of this vector.

	void setDiff(Point3& a, Point3& b)
	// Makes this vector the vector from b to a.
	{ 
		x = a.x - b.x; y = a.y - b.y; z = a.z - b.z; 
	}

	void normalize() 
	// Adjusts this vector to unit length.
	{		
		double sizeSq = x * x + y * y + z * z;
		if(sizeSq < 0.0000001)
		{
			cerr << "\nnormalize() sees vector (0,0,0)!";
			return; // does nothing to zero vectors;
		}
		double scaleFactor = 1.0/(double)sqrt(sizeSq);
		x *= scaleFactor; y *= scaleFactor; z *= scaleFactor;
	}

	Vector3 cross(Vector3 b) 
	// Return this vector cross b.
	{
	   Vector3 c(y*b.z - z*b.y, z*b.x - x*b.z, x*b.y - y*b.x);
	   return c;
	}

	double dot(Vector3 b) 
	// Returns this vector dotted with b.
	{ 
		return x * b.x + y * b.y + z * b.z; 
	}

	/* Added by Phil, 11/25/08 */
	double length()
	{
		return sqrt(x*x + y*y + z*z);
	}

	friend Vector3 operator+(const Vector3& v1, const Vector3& v2)
	// Returns the sum of vectors v1 and v2.
	{
		Vector3 sum(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
		return sum; 
	}

	friend Vector3 operator-(const Vector3& v1, const Vector3& v2)
	// Returns the vector that results when v2 is subtracted from v1.
	{
		Vector3 diff(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
		return diff; 
	}
	friend Vector3 operator-(const Vector3& v)
	// Returns the negative of v, the vector of the same length as v
	// pointing in the opposite direction.
	{
		Vector3 neg(-v.x, -v.y, -v.z);
		return neg; 
	}

	friend Vector3 operator*(double alpha, const Vector3& v)
	// Returns the vector that results when v is multiplied on the left
	// by scalar alpha.
	{
		Vector3 sum(alpha * v.x, alpha * v.y, alpha * v.z);
		return sum; 
	}

	friend Vector3 operator*(const Vector3& v, double alpha)
	// Returns the vector that results when v is multiplied on the right
	// by scalar alpha.
	{
		return alpha * v; 
	}
}; 

#endif
